(* ::Package:: *)

BeginPackage["Layout`"]


ClearAll[OptimizeLayout]

Options[OptimizeLayout] = {
	CC -> 0.2, (* Relative strength of the repel potential *)
	KK -> 1,   (* Characteristic scale *)
	pow -> 2   (* Power of the distance in the repel potential *),
	Release -> {},
	Width -> 4,
	Height -> 3,
	Method -> Automatic
}

OptimizeLayout[in_Integer -> out_Integer, vNum_Integer, edges_List, OptionsPattern[]] := 
	Module[{
	CC = OptionValue[CC],
	KK = OptionValue[KK],
	pow = OptionValue[pow],
	release = OptionValue[Release],
	Width = OptionValue[Width],
	Height = OptionValue[Height],
	method = OptionValue[Method],
	pos, x, y, vars,
	V, keys, min, rules
	}, 
		pos = Association@Join[
			Table[-2i+1 -> {-(Width/2), Height/2-Height/in (i-1/2)}, {i, in}],
			Table[-2i -> {Width/2, Height/2-Height/out (i-1/2)}, {i, out}],
			Table[i -> {x[i], y[i]}, {i, vNum}]
		];
		vars = Table[{x[i], y[i]}, {i, vNum}];
		Do[
			AppendTo[pos, r -> {x[r], y[r]}];
			AppendTo[vars, {x[r], y[r]}];,
			{r, DeleteDuplicates[release]}
		];
		keys = Keys[pos];
		V = Plus[
				Total[edges /. Edge[i_, j_, type___] :> If[
					i=!=j && MemberQ[keys, i] && MemberQ[keys, j], 
					Va[pos[i], pos[j], KK], 
					0
				]],
				Sum[
					Vr[pos[keys[[i]]], pos[keys[[j]]], CC, KK, pow],
					{i, Length[keys]}, {j, i+1, Length[keys]}
				]
			];
		{min, rules} = NMinimize[V, Flatten@vars, Method -> method];
		Return[pos/.rules]
	]


ClearAll[Edge]


ClearAll[Vr, Va]

Vr[{x1_, y1_}, {x2_, y2_}, CC_, KK_, pow_] := 
	With[{dx = {x2, y2} - {x1, y1}},
		1/(pow-1) (CC KK^(1+pow))/Norm[dx]^(pow-1)
	]

Va[{x1_, y1_}, {x2_, y2_}, KK_] := 
	With[{dx = {x2, y2}- {x1, y1}},
		1/3 Norm[dx]^3/KK
	]


EndPackage[]
